package com.cout970.magneticraft.registry

import com.cout970.magneticraft.api.conveyor.IConveyor
import com.cout970.magneticraft.api.conveyor.Route
import com.cout970.magneticraft.api.core.INode
import com.cout970.magneticraft.api.core.INodeHandler
import com.cout970.magneticraft.api.core.ITileRef
import com.cout970.magneticraft.api.core.NodeID
import com.cout970.magneticraft.systems.tilemodules.conveyor.BoxedItem
import net.minecraft.block.Block
import net.minecraft.entity.Entity
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTBase
import net.minecraft.nbt.NBTTagCompound
import net.minecraft.tileentity.TileEntity
import net.minecraft.util.EnumFacing
import net.minecraft.util.math.BlockPos
import net.minecraft.world.World
import net.minecraftforge.common.capabilities.Capability
import net.minecraftforge.common.capabilities.CapabilityInject
import net.minecraftforge.common.capabilities.CapabilityManager
import net.minecraftforge.common.capabilities.ICapabilityProvider
import net.minecraftforge.energy.IEnergyStorage
import net.minecraftforge.fluids.capability.IFluidHandler
import net.minecraftforge.fluids.capability.IFluidHandlerItem
import net.minecraftforge.items.IItemHandler

/**
 * Stores instances of Capabilities
 * to use them you need to add !! at the end
 * for example:
 * ITEM_HANDLER!!.fromTile(tile)
 */

@CapabilityInject(IItemHandler::class)
var ITEM_HANDLER: Capability<IItemHandler>? = null

@CapabilityInject(IConveyor::class)
var CONVEYOR_BELT: Capability<IConveyor>? = null

/**
 * This is called on the server and the client at preInit
 */
fun registerCapabilities() {
    CapabilityManager.INSTANCE.apply {
        register(IConveyor::class.java, EmptyStorage()) { DefaultConveyor() }
    }
}

/**
 * Extension functions to get capabilities from TileEntities, Blocks and Items
 */
fun <T> Capability<T>.fromTile(tile: TileEntity, side: EnumFacing? = null): T? {
    if (tile.hasCapability(this, side)) {
        return tile.getCapability(this, side)
    }
    return null
}

fun <T> Capability<T>.fromEntity(tile: Entity, side: EnumFacing? = null): T? {
    if (tile.hasCapability(this, side)) {
        return tile.getCapability(this, side)
    }
    return null
}

fun <T> Capability<T>.fromBlock(block: Block, side: EnumFacing? = null): T? {
    if (block is ICapabilityProvider && block.hasCapability(this, side)) {
        return block.getCapability(this, side)
    }
    return null
}

fun <T> Capability<T>.fromItem(tile: ItemStack): T? {
    if (tile.hasCapability(this, null)) {
        return tile.getCapability(this, null)
    }
    return null
}

fun <T> TileEntity.getOrNull(cap: Capability<T>?, side: EnumFacing?): T? {
    cap ?: return null
    if (this.hasCapability(cap, side)) {
        return this.getCapability(cap, side)
    }
    return null
}


/**
 * Empty implementation of IStorage
 * At some point this should be changed, or just ignored
 */
class EmptyStorage<T> : Capability.IStorage<T> {

    override fun writeNBT(capability: Capability<T>?, instance: T, side: EnumFacing?): NBTBase? = NBTTagCompound()

    override fun readNBT(capability: Capability<T>?, instance: T, side: EnumFacing?, nbt: NBTBase?) = Unit
}

class DefaultConveyor : IConveyor {
override fun getFacing(): EnumFacing = EnumFacing.NORTH
    override fun getBoxes(): MutableList<BoxedItem> = mutableListOf()
    override fun getLevel(): Int = 0
    override fun addItem(stack: ItemStack, simulated: Boolean): Boolean = false
    override fun addItem(stack: ItemStack, side: EnumFacing, oldRoute: Route): Boolean = false
}